﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using SH;

namespace MTS
{
    class mtInterface : Imt
    {
        protected mtVHost m_pHost;
        protected mtInterfaceManager m_interfaceManager;
        protected string interfaceName;
        MTSDLLWrap _mts;
       
        Dictionary<int, emProgramType> mapEpic = new Dictionary<int, emProgramType>();

        public mtInterface(string name)
        {
            interfaceName = name;

            _mts = MTSDLLWrap.getInstance();
        }

        protected virtual shErrorCode _Initialize() { return shErrorCode.sh_ec_NotImplement; }

        public shErrorCode Initialize(mtVHost pHost)
        {
            m_pHost = pHost;

            m_interfaceManager = m_pHost.GetInterfaceManager();

            return _Initialize();
        }

        public string GetInterfaceName()
        {
            return interfaceName;
        }

        public shErrorCode BindEpic(emProgramType pt, int nClassID)
        {
            MTSSerializer sc = new MTSSerializer();
            sc.serialize(ref pt);
            sc.serialize(ref nClassID);

            var ec = __InvokeOneWay(0, 4, sc);

            if (ec != 0)
            {
                return (shErrorCode)ec;
            }
           
            mapEpic.Add(nClassID, pt);

            return shErrorCode.sh_ec_Success;
        }

        public mtVHost GetVHost() { return m_pHost; }

        public Imt QueryInterface(string interfaceName)
        {
            if (this.interfaceName == interfaceName)
                return this;
            else
            {
                return m_interfaceManager.QueryInterface(interfaceName);
            }
        }

        public shErrorCode SetCallback(ImtCallback callback)
        {

            if (m_interfaceManager != null)
            {
                return m_interfaceManager.SetCallback(callback);
            }
            else
                return shErrorCode.sh_ec_NotActive;

        }

        //public shErrorCode __OnInvokeOneWay(mtDataPacket pPacket)
        //{
        //    return shErrorCode.sh_ec_NotImplement;
        //}

        //public shErrorCode __OnInvokeTwoWay(mtDataPacket pInPacket, mtDataPacket pOutPacket)
        //{
        //    return shErrorCode.sh_ec_NotImplement;
        //}

        public shErrorCode __InvokeOneWay(int nClassID, int nFuncID, MTSSerializer sc)
        {
            emProgramType pt;

            if (nClassID != 0)
            {
                if (mapEpic.TryGetValue(nClassID, out pt) == false)
                    return shErrorCode.sh_ec_InvalidArgs;
            }

            var IvkParam = mtCHelptr.MakeInvokeParam(nClassID, nFuncID);
            var dataParam = mtCHelptr.MakeDataParam(sc.ToArray());

            var ec = _mts.mtInvokeOneWay(GetVHost().Handle, ref IvkParam, ref dataParam);

            return (shErrorCode)ec;
        }

        public shErrorCode __InvokeOneWay(int nClassID, int nFuncID, emProgramType pt, MTSSerializer sc)
        {

            var IvkParam = mtCHelptr.MakeInvokeParam(nClassID, nFuncID, pt);
            var dataParam = mtCHelptr.MakeDataParam(sc.ToArray());

            var ec = _mts.mtInvokeOneWay(GetVHost().Handle, ref IvkParam, ref dataParam);

            return (shErrorCode)ec;
        }

        public shErrorCode __InvokeOneWay(int nClassID, int nFuncID, string token, MTSSerializer sc)
        {

            var IvkParam = mtCHelptr.MakeInvokeParam(nClassID, nFuncID, token);
            var dataParam = mtCHelptr.MakeDataParam(sc.ToArray());

            var ec = _mts.mtInvokeOneWay(GetVHost().Handle, ref IvkParam, ref dataParam);

            return (shErrorCode)ec;
        }

        public shErrorCode __InvokeTwoWay(int nClassID, int nFuncID, ref MTSSerializer sc)
        {
            emProgramType pt;

            if (nClassID != 0)
            {
                if (mapEpic.TryGetValue(nClassID, out pt) == false)
                    return shErrorCode.sh_ec_InvalidArgs;
            }

            var IvkParam = mtCHelptr.MakeInvokeParam(nClassID, nFuncID);
            var dataParamIn = mtCHelptr.MakeDataParam(sc.ToArray());
            var dataParamOut = mtCHelptr.MakeEmptyDataParam();

            var ec = _mts.mtInvokeTwoWay(GetVHost().Handle, ref IvkParam, ref dataParamIn, ref dataParamOut);

            if (ec == 0)
            {
                byte[] buf = mtCHelptr.DataParamOutToBytes(dataParamOut);

                if (buf.Length > 0)
                {
                    sc = new MTSSerializer(buf, emReadWriteType.emRWT_Read);
                }

            }

            return (shErrorCode)ec;
        }

        public shErrorCode __InvokeTwoWay(int nClassID, int nFuncID, string token, ref MTSSerializer sc)
        {

            var IvkParam = mtCHelptr.MakeInvokeParam(nClassID, nFuncID, token);
            var dataParamIn = mtCHelptr.MakeDataParam(sc.ToArray());
            var dataParamOut = mtCHelptr.MakeEmptyDataParam();

            var ec = _mts.mtInvokeTwoWay(GetVHost().Handle, ref IvkParam, ref dataParamIn, ref dataParamOut);

            if (ec == 0)
            {
                byte[] buf = mtCHelptr.DataParamOutToBytes(dataParamOut);

                if (buf.Length > 0)
                {
                    sc = new MTSSerializer(buf, emReadWriteType.emRWT_Read);
                }
            }

            return (shErrorCode)ec;
        }

        public shErrorCode __InvokeTwoWay(int nClassID, int nFuncID, emProgramType pt, ref MTSSerializer sc)
        {

            var IvkParam = mtCHelptr.MakeInvokeParam(nClassID, nFuncID, pt);
            var dataParamIn = mtCHelptr.MakeDataParam(sc.ToArray());
            var dataParamOut = new mtCDataParam();

            var ec = _mts.mtInvokeTwoWay(GetVHost().Handle, ref IvkParam, ref dataParamIn, ref dataParamOut);

            if (ec == 0)
            {
                byte[] buf = mtCHelptr.DataParamOutToBytes(dataParamOut);

                if (buf.Length > 0)
                {
                    sc = new MTSSerializer(buf, emReadWriteType.emRWT_Read);
                }
            }

            return (shErrorCode)ec;
        }
    }

    class mtOuterface<T> : _ImtOuterface where T : ImtCallback
    {
        protected mtInterfaceManager m_pInterfaceManager;

        protected string m_interfaceName;
        protected mtVHost m_pHost;

        protected int m_nClassID = 0;

        protected T m_pCallback;

        public shErrorCode Initialize(mtVHost pHost)
        {
            m_pHost = pHost;
            m_pInterfaceManager = m_pHost.GetInterfaceManager();

            return shErrorCode.sh_ec_Success;
        }

        public int GetClassID() { return m_nClassID; }

        public string GetInterfaceName() { return m_interfaceName; }

        public shErrorCode SetInnerCallback(ImtCallback callback)
        {
            m_pCallback = (T)callback;

            return shErrorCode.sh_ec_Success;
        }

        public ImtCallback GetCallback()
        {
            return m_pCallback;
        }

        virtual protected shErrorCode OnRequest(int nClassID, int nFuncID, string token, ref MTSSerializer sc)
        {
            return shErrorCode.sh_ec_NotImplement;
        }

        virtual public shErrorCode _OnInvokeOneWay(int nClassID, int nFuncID, string token, MTSSerializer sc)
        {
            var ec = OnRequest(nClassID, nFuncID, token, ref sc);


            return ec;

            //if (ec != shErrorCode.sh_ec_NoInterface)
            //{
                
            //    return shErrorCode.sh_ec_Success;
            //}
            //else
            //{
            //    return shErrorCode.sh_ec_NoInterface;
            //}
        }

       virtual  public  shErrorCode _OnInvokeTwoWay(int nClassID, int nFuncID, string token, ref MTSSerializer sc)
        {
            var ec = OnRequest(nClassID, nFuncID, token, ref sc);

            if (sc.isRead())
            {
                sc = new MTSSerializer();
            }

            return ec;

            //if (ec != shErrorCode.sh_ec_NoInterface)
            //{
            //    sc.serialize(ref ec);
            //  //  return ec;
            //    return shErrorCode.sh_ec_Success;
            //}
            //else
            //{
            //    return shErrorCode.sh_ec_NoInterface;
            //}

        }

    }

    class mtInterfaceManager
    {
        mtVHost m_pHost;

        readonly object m_mtxIntrerface = new object();
        Dictionary<string, mtInterface> m_mapClientInterfaceByTypID = new Dictionary<string, mtInterface>();
        Dictionary<string, mtInterface> m_mapClientInterface = new Dictionary<string, mtInterface>();

        Dictionary<string, mtInterface> m_mapServerInterfaceByTypID = new Dictionary<string, mtInterface>();
        Dictionary<string, mtInterface> m_mapServerInterface = new Dictionary<string, mtInterface>();

        readonly object m_mtxOuterface = new object();

        Dictionary<string, _ImtOuterface> m_mapClientCallbackInterface = new Dictionary<string, _ImtOuterface>();
        Dictionary<string, _ImtOuterface> m_mapClientCallbackInterfaceByTypID = new Dictionary<string, _ImtOuterface>();
        Dictionary<int, _ImtOuterface> m_mapClientCallbackInterfaceByClsID = new Dictionary<int, _ImtOuterface>();
        Dictionary<string, _ImtOuterface> m_mapServerCallbackInterface = new Dictionary<string, _ImtOuterface>();
        Dictionary<string, _ImtOuterface> m_mapServerCallbackInterfaceByTypID = new Dictionary<string, _ImtOuterface>();
        Dictionary<int, _ImtOuterface> m_mapServerCallbackInterfaceByClsID = new Dictionary<int, _ImtOuterface>();

        public mtInterfaceManager(mtVHost host)
        {
            m_pHost = host;
        }
        public shErrorCode Initialize(mtRegisterInfo info)
        {
            MakeClientInterface(info);

            foreach (var it in m_mapClientInterfaceByTypID)
            {
                var pInterface = it.Value;

                m_mapClientInterface.Add(pInterface.GetInterfaceName(), pInterface);
                pInterface.Initialize(m_pHost);
            }

            foreach (var it in m_mapClientCallbackInterfaceByTypID)
            {
                var pOuterface = it.Value;

                m_mapClientCallbackInterface.Add(pOuterface.GetInterfaceName(), pOuterface);

                m_mapClientCallbackInterfaceByClsID.Add(pOuterface.GetClassID(), pOuterface);

                pOuterface.Initialize(m_pHost);

            }

            MakeServerInterface(info);

            foreach (var it in m_mapServerInterfaceByTypID)
            {
                var pInterface = it.Value;

                m_mapServerInterface.Add(pInterface.GetInterfaceName(), pInterface);
                pInterface.Initialize(m_pHost);
            }

            foreach (var it in m_mapServerCallbackInterfaceByTypID)
            {
                var pOuterface = it.Value;

                m_mapServerCallbackInterface.Add(pOuterface.GetInterfaceName(), pOuterface);

                m_mapServerCallbackInterfaceByClsID.Add(pOuterface.GetClassID(), pOuterface);

                pOuterface.Initialize(m_pHost);
            }

            return shErrorCode.sh_ec_Success;
        }


        public shErrorCode Start()
        {
            return shErrorCode.sh_ec_Success;
        }

        public shErrorCode Stop()
        {
            return shErrorCode.sh_ec_Success;
        }

        shErrorCode MakeClientInterface(mtRegisterInfo info)
        {
            switch (info.ProgramType)
            {
                case emProgramType.emPT_RCS:
                case emProgramType.emPT_CSS:
                    {

                        var pSysManage = new mtSysManage();

                        m_mapClientInterfaceByTypID.Add(typeof(mtSysManage).GUID.ToString(), pSysManage);

                        // var pRCS = new mtRCS();
                        // m_mapClientInterfaceByTypID.insert(typeof(mtRCS).GUID.ToString(), pRCS);

                        var pSysManagerCallback = new mtSysManageCallback();

                        m_mapClientCallbackInterfaceByTypID.Add(typeof(mtSysManageCallback).GUID.ToString(), pSysManagerCallback);

                        // var pRCSCallback = new mtRCSCallback();

                        // m_mapClientCallbackInterfaceByTypID.insert(typeof(mtRCSCallback).GUID.ToString(), pRCSCallback);
                    }
                    break;
                case emProgramType.emPT_DMS:
                    {
                        var pSysManage = new mtSysManage();

                        m_mapClientInterfaceByTypID.Add(typeof(mtSysManage).GUID.ToString(), pSysManage);

                        var pSysManagerCallback = new mtSysManageCallback();

                        m_mapClientCallbackInterfaceByTypID.Add(typeof(mtSysManageCallback).GUID.ToString(), pSysManagerCallback);
                    }
                    break;
                case emProgramType.emPT_IPC:
                case emProgramType.emPT_IPSS:
                    {
                        var pSysManage = new mtSysManage();

                        m_mapClientInterfaceByTypID.Add(typeof(mtSysManage).GUID.ToString(), pSysManage);

                        var pSysManagerCallback = new mtSysManageCallback();

                        m_mapClientCallbackInterfaceByTypID.Add(typeof(mtSysManageCallback).GUID.ToString(), pSysManagerCallback);
                    }
                    break;
                default:
                    {

                    }
                    break;

            }

            return shErrorCode.sh_ec_Success;
        }

        shErrorCode MakeServerInterface(mtRegisterInfo info)
        {
            switch (info.ProgramType)
            {
                case emProgramType.emPT_RCS:
                case emProgramType.emPT_CSS:
                    {
                        var pSysManageServer = new mtSysManageServer();

                        m_mapServerInterfaceByTypID.Add(typeof(mtSysManageServer).GUID.ToString(), pSysManageServer);

                        var pCSS = new mtCSSServer();

                        m_mapServerInterfaceByTypID.Add(typeof(mtCSSServer).GUID.ToString(), pCSS);

                        var pSysManagerServerCallback = new mtSysManageServerCallback();

                        m_mapServerCallbackInterfaceByTypID.Add(typeof(mtSysManageServerCallback).GUID.ToString(), pSysManagerServerCallback);

                        var pServerCallback = new mtCSSServerCallback();

                        m_mapServerCallbackInterfaceByTypID.Add(typeof(mtCSSServerCallback).GUID.ToString(), pServerCallback);

                    }
                    break;
                case emProgramType.emPT_DMS:
                    {
                        var pSysManageServer = new mtSysManageServer();

                        m_mapServerInterfaceByTypID.Add(typeof(mtSysManageServer).GUID.ToString(), pSysManageServer);

                        var pDMS = new mtDMSServer();

                        m_mapServerInterfaceByTypID.Add(typeof(mtDMSServer).GUID.ToString(), pDMS);

                        var pSysManagerServerCallback = new mtSysManageServerCallback();

                        m_mapServerCallbackInterfaceByTypID.Add(typeof(mtSysManageServerCallback).GUID.ToString(), pSysManagerServerCallback);

                        var pServerCallback = new mtDMSServerCallback();

                        m_mapServerCallbackInterfaceByTypID.Add(typeof(mtDMSServerCallback).GUID.ToString(), pServerCallback);
                    }
                    break;
                case emProgramType.emPT_IPSS:
                    {
                        var pSysManageServer = new mtSysManageServer();
                        m_mapServerInterfaceByTypID.Add(typeof(mtSysManageServer).GUID.ToString(), pSysManageServer);
                        var pIPSS = new mtIPSServer();
                        m_mapServerInterfaceByTypID.Add(typeof(mtIPSServer).GUID.ToString(), pIPSS);

                        var pSysManagerServerCallback = new mtSysManageServerCallback();

                        m_mapServerCallbackInterfaceByTypID.Add(typeof(mtSysManageServerCallback).GUID.ToString(), pSysManagerServerCallback);

                        var pServerCallback = new mtIPSServerCallback();

                        m_mapServerCallbackInterfaceByTypID.Add(typeof(mtIPSServerCallback).GUID.ToString(), pServerCallback);
                    }
                    break;
                case emProgramType.emPT_SMS:
                    {
                        var pSysManageServer = new mtSysManageServer();
                        m_mapServerInterfaceByTypID.Add(typeof(mtSysManageServer).GUID.ToString(), pSysManageServer);

                        var pSCS = new mtSMSServer();
                        m_mapServerInterfaceByTypID.Add(typeof(mtSMSServer).GUID.ToString(), pSCS);

                        var pSysManagerServerCallback = new mtSysManageServerCallback();

                        m_mapServerCallbackInterfaceByTypID.Add(typeof(mtSysManageServerCallback).GUID.ToString(), pSysManagerServerCallback);

                        var pSMSServerCallback = new mtSMSServerCallback();

                        m_mapServerCallbackInterfaceByTypID.Add(typeof(mtSMSServerCallback).GUID.ToString(), pSMSServerCallback);
                    }
                    break;
                default:
                    {

                    }
                    break;

            }


            return shErrorCode.sh_ec_Success;
        }

        public mtInterface QueryInterface(string interfaceName)
        {
            mtInterface pInterface;

            lock (m_mtxIntrerface)
            {
                if (m_mapServerInterface.TryGetValue(interfaceName, out pInterface))
                {
                    return pInterface;
                }

                if (m_mapClientInterface.TryGetValue(interfaceName, out pInterface))
                {
                    return pInterface;
                }

            }

            return null;
        }

        public _Ty GetClientInterface<_Ty>() where _Ty : mtInterface
        {
            Type type = typeof(_Ty);

            mtInterface pInterface;

            lock (m_mtxIntrerface)
            {
                if (m_mapClientInterfaceByTypID.TryGetValue(type.GUID.ToString(), out pInterface))
                {
                    return (_Ty)pInterface;
                }
                else
                {
                    return null;
                }
            }
        }

        public _Ty GetServerInterface<_Ty>() where _Ty : mtInterface
        {
            Type type = typeof(_Ty);

            mtInterface pInterface;

            lock (m_mtxIntrerface)
            {
                if (m_mapServerInterfaceByTypID.TryGetValue(type.GUID.ToString(), out pInterface))
                {
                    return (_Ty)pInterface;
                }
                else
                {
                    return null;
                }
            }
        }

        public shErrorCode SetCallback(ImtCallback callback)
        {
            lock (m_mtxOuterface)
            {
                _ImtOuterface pOuterface;

                 if (m_mapServerCallbackInterface.TryGetValue(callback.GetInterfaceName(), out pOuterface))
                {
                    return pOuterface.SetInnerCallback(callback);
                }
                else if(m_mapClientCallbackInterface.TryGetValue(callback.GetInterfaceName(), out pOuterface))
                {
                    return pOuterface.SetInnerCallback(callback);
                }


                return shErrorCode.sh_ec_NoInterface;
            }

        }

        public _Ty GetClientOuterface<_Ty>() where _Ty : _ImtOuterface
        {
            Type type = typeof(_Ty);

            _ImtOuterface pOuterface;

            lock (m_mtxOuterface)
            {
                if (m_mapClientCallbackInterfaceByTypID.TryGetValue(type.GUID.ToString(), out pOuterface))
                {
                    return (_Ty)(pOuterface);
                }
                else
                    return (_Ty)(pOuterface);
            }

        }


        public _Ty GetServerOuterface<_Ty>() where _Ty : _ImtOuterface
        {
            Type type = typeof(_Ty);

            _ImtOuterface pOuterface;

            lock (m_mtxOuterface)
            {
                if (m_mapServerCallbackInterfaceByTypID.TryGetValue(type.GUID.ToString(), out pOuterface))
                {
                    return (_Ty)(pOuterface);
                }
                else
                    return (_Ty)(pOuterface);
            }

        }

        public mtSysManage GetSysManage()
        {
            return GetClientInterface<mtSysManage>();
        }

        public mtSysManageServer GetSysManageServer()
        {
            return GetServerInterface<mtSysManageServer>();
        }

        public _ImtOuterface GetClientOuterface(int nClass)
        {
            lock (m_mtxOuterface)
            {
                _ImtOuterface pOuterface;

                if (m_mapClientCallbackInterfaceByClsID.TryGetValue(nClass, out pOuterface))
                {
                    return pOuterface;
                }
            }

            return null;
        }

        public _ImtOuterface GetServerOuterface(int nClass)
        {
            lock (m_mtxOuterface)
            {
                _ImtOuterface pOuterface;

                if (m_mapServerCallbackInterfaceByClsID.TryGetValue(nClass, out pOuterface))
                {
                    return pOuterface;
                }
            }

            return null;
        }
    }
}
